package su.theravada.jpalireader;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.text.html.HTMLDocument;

import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.index.TieredMergePolicy;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

import su.theravada.jpalireader.util.PaliUtil;
import su.theravada.jpalireader.util.SqlUtil;
import su.theravada.jpalireader.util.UTF8Control;
import su.theravada.jpalireader.util.ZipUtil;


/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class IndexingProgressDlg extends javax.swing.JDialog {
	private JLabel ctlIndexingInProgress;
	private JProgressBar ctlProgressBar;
	private JButton ctlCancel;
	private IndexingTask _IndexingTask;
	public boolean DialogSuccess;
	
	public enum IndexObjectType
	{
		PALICANON,
		PED
	}
	
	public IndexingProgressDlg(JFrame frame,IndexObjectType nIndexWhat) {
		super(frame);
		initGUI();
		
		_IndexingTask=new IndexingTask(nIndexWhat);
		_IndexingTask.addPropertyChangeListener(new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
	             if ("progress".equals(evt.getPropertyName())) {
	            	 ctlProgressBar.setValue((Integer)evt.getNewValue());
	             }	
	             
	             if ("state".equals(evt.getPropertyName())
	                     && SwingWorker.StateValue.DONE == evt.getNewValue()) {
	                 DialogSuccess=true;
	                 setVisible(false);
	             }
			} 						
		});
		
		_IndexingTask.execute();
	}
	
	private void initGUI() {
		try {
			ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
			{
				getContentPane().setLayout(null);
				setModal(true);
				this.setResizable(false);
			}
			{
				ctlIndexingInProgress = new JLabel();
				getContentPane().add(ctlIndexingInProgress, "Center");
				ctlIndexingInProgress.setText(res_strings.getString("IndexingInProgress"));
				ctlIndexingInProgress.setBounds(80, 7, 246, 19);
			}
			{
				ctlCancel = new JButton();
				getContentPane().add(ctlCancel);
				ctlCancel.setText(res_strings.getString("Cancel"));
				ctlCancel.setBounds(132, 73, 111, 22);
				ctlCancel.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						ctlCancelActionPerformed(evt);
					}
				});
			}
			{
				ctlProgressBar = new JProgressBar(0,100);
				getContentPane().add(ctlProgressBar);
				ctlProgressBar.setBounds(12, 38, 356, 23);
			}
			this.setSize(388, 135);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void ctlCancelActionPerformed(ActionEvent evt) {
		_IndexingTask.cancel(true);
        DialogSuccess=false;
		setVisible(false);
	}

	class IndexingTask extends SwingWorker<Object,Integer>
	{
		IndexObjectType _nIndexWhat;
		String[] _arrStripPatterns={"\n","<![^<]*>","<script.+?</script>","<head.+</head>"};
		String[] _arrReplacePatterns={"(?:&([a-z]|[A-Z])+;)","<([a-z]|[A-Z])+[^<]*>","</([a-z]|[A-Z])+[^<]*>","\\s{2,}"};
		ArrayList<Pattern> _arrStripPatternObjects;
		ArrayList<Pattern> _arrReplacePatternObjects;
		
		public IndexingTask(IndexObjectType nIndexWhat)
		{
			_nIndexWhat=nIndexWhat;
			
			_arrStripPatternObjects=new ArrayList<Pattern>();
			for(String strStripPattern : _arrStripPatterns)
				_arrStripPatternObjects.add(Pattern.compile(strStripPattern,Pattern.CASE_INSENSITIVE));

			_arrReplacePatternObjects=new ArrayList<Pattern>();
			for(String strReplacePattern : _arrReplacePatterns)
				_arrReplacePatternObjects.add(Pattern.compile(strReplacePattern,Pattern.CASE_INSENSITIVE));			
		}
		
		@Override
		protected Object doInBackground() throws Exception {

			if(_nIndexWhat==IndexObjectType.PALICANON)
				IndexCanon();
			else
				IndexPED();
			
			return null;
		}
	
		private void IndexCanon()
		{			
	        ResultSet rs = null;
	        ResultSet rsCount=null;
	        Statement objStatement=null;
	        IndexWriter writer=null;
	        
			try
			{
				StandardAnalyzer objAnayzer=new StandardAnalyzer(Version.LUCENE_36,PaliUtil.getPaliStopWords());
				
				IndexWriterConfig objConfig=new IndexWriterConfig(Version.LUCENE_36,objAnayzer);
				((TieredMergePolicy)objConfig.getMergePolicy()).setUseCompoundFile(true);
				FSDirectory objIndexDir=FSDirectory.open(new File(Paths.CanonIndexPath));
				writer=new IndexWriter(objIndexDir,objConfig);
				
				objStatement=MainWindow.getDBConnection().createStatement();
				rsCount=objStatement.executeQuery("SELECT COUNT(*) FROM Files");
				rsCount.next();
				int nRowCount=rsCount.getInt(1);
				
				rs=objStatement.executeQuery("SELECT FileID,FileName FROM Files");
				
				int CurIndex=1;
				
				while(rs.next() && !isCancelled())
				{
					String strFileContent=ZipUtil.LoadContentFile(rs.getString("FileName"), Paths.CanonPath);
			    
					Document objDoc=new Document();
					//no need to store it because we always have the file available in zip
					Field objTextField=new Field("text",false,ExtractPlainText(strFileContent),Field.Store.NO,Field.Index.ANALYZED,
							Field.TermVector.WITH_POSITIONS_OFFSETS);
					objTextField.setOmitNorms(true); //so lenth of the document does not count
					objDoc.add(objTextField);
					NumericField objFileIDField=new NumericField("file",Field.Store.YES,true);
					objFileIDField.setIntValue(rs.getInt("FileID"));

					objDoc.add(objFileIDField);
					writer.addDocument(objDoc);											
					
					setProgress(100 * CurIndex++ / nRowCount);
				}				
				
				if(!isCancelled())
					writer.forceMerge(1);			
			}
			catch(SQLException sqle)
			{		
				SqlUtil.ReportSQLException(sqle);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			finally
			{
				SqlUtil.CloseResultSet(rs);
				SqlUtil.CloseResultSet(rsCount);
				SqlUtil.CloseStatement(objStatement);
				
				try {
					writer.close();
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}						
		}
		
		private void IndexPED()
		{
			IndexWriter writer=null;
			try
			{
				StandardAnalyzer objAnayzer=new StandardAnalyzer(Version.LUCENE_36,PaliUtil.getPaliStopWords());
				IndexWriterConfig objConfig=new IndexWriterConfig(Version.LUCENE_36,objAnayzer);	
				((TieredMergePolicy)objConfig.getMergePolicy()).setUseCompoundFile(true);
				FSDirectory objIndexDir=FSDirectory.open(new File(Paths.PEDIndexPath));
				writer=new IndexWriter(objIndexDir,objConfig);
				
				int PEDLetters = 38;
				Pattern objLetterPattern=Pattern.compile("<span class=letter><b>([^<]+)</b></span>",Pattern.CASE_INSENSITIVE);
				
				for(int i=1;i<PEDLetters;i++)
				{					
					String strFileName=new DecimalFormat("00").format(i);
					String strFileContent=ZipUtil.LoadContentFile(strFileName, Paths.PEDPath);
					
					Document objDoc=new Document();
					//no need to store it because we always have the file available in zip
					Field objTextField=new Field("text",false,ExtractPlainText(strFileContent),Field.Store.NO,Field.Index.ANALYZED,
							Field.TermVector.WITH_POSITIONS_OFFSETS);
					objTextField.setOmitNorms(true);
					objDoc.add(objTextField);
					
					Matcher objMatcher=objLetterPattern.matcher(strFileContent);
					objMatcher.find();
					String strPaliLetter=objMatcher.group(1);
					objDoc.add(new Field("letter", strPaliLetter, Field.Store.YES, Field.Index.NO));
					objDoc.add(new Field("ID", strFileName, Field.Store.YES, Field.Index.NO));

					writer.addDocument(objDoc);											
					
					setProgress(100 * (i-1) / PEDLetters);
					
					if(isCancelled())
						break;
				}
				
				if(!isCancelled())
					writer.forceMerge(1);				
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}	
			finally
			{
				try {
					writer.close();
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}		
		
		private String ExtractPlainText(String strHTMLDocument)
		{
			String strRetVal=strHTMLDocument;
			
			for(Pattern objStripPattern: _arrStripPatternObjects)
				strRetVal=objStripPattern.matcher(strRetVal).replaceAll("");			
			
			for(Pattern objReplacePattern: _arrReplacePatternObjects)
				strRetVal=objReplacePattern.matcher(strRetVal).replaceAll(" ");	
			
			return strRetVal;
		}
	}
}
